Imports ccapps.persistent.Telnet

Namespace persistent.Telnet.Scripting
    Public Class Script

        Public Shared Sub RunScript(ByVal p_host As String, ByVal p_username As String, ByVal p_password As String, ByVal p_commandList() As String)
            Dim l_commandList(p_commandList.Length - 1) As ConditionalCommand
            For index As Integer = 0 To p_commandList.Length - 1
                l_commandList(index) = New ConditionalCommand(p_commandList(index), "/>")
            Next
            RunConditionalScript(p_host, p_username, p_password, l_commandList)
        End Sub

        Public Shared Sub RunConditionalScript(ByVal p_host As String, ByVal p_username As String, ByVal p_password As String, ByVal p_commandList() As ConditionalCommand)
            RunConditionalScript(p_host, p_username, p_password, 6, p_commandList)
        End Sub

        Public Shared Sub RunConditionalScript(ByVal p_host As String, ByVal p_username As String, ByVal p_password As String, ByVal environmentNumber As Integer, ByVal p_commandList() As ConditionalCommand)
            Dim l_databaseConnection As New OracleClient.OracleConnection(GlobalVar.OraConnStr)
            Dim l_afterLoginExpect As String = "/>"
            Dim l_isProductionEnvironment = l_databaseConnection.DataSource = "BSPR"

            If l_databaseConnection.DataSource = "BSPR" OrElse l_databaseConnection.DataSource = "BSPR_133" Then
                l_afterLoginExpect = "/>"
            ElseIf l_databaseConnection.DataSource = "BSPRD" OrElse l_databaseConnection.DataSource = "BSPR_DEV" Then
                l_afterLoginExpect = "settings"
            End If

            'If Not l_isProductionEnvironment Then l_afterLoginExpect = "(1/2/3/4/5/6/7/8/9/10)?"
            'If Not l_isProductionEnvironment Then l_afterLoginExpect = "settings"

            Dim l_request As New ccapps.persistent.Telnet.Scripting.Script(p_host, 23, 90000)

            Dim l_oracle_str As String = GlobalVar.OraConnStr
            l_request.AddLine(New ScriptLine(p_username, "Password"))
            l_request.AddLine(New ScriptLine(p_password, l_afterLoginExpect))

            If Not l_isProductionEnvironment Then
                l_request.AddLine(New ScriptLine(environmentNumber.ToString(), "/>"))
            End If

            'If l_oracle_str.ToUpper().IndexOf("BSPR_BCV") > 0 _
            '        Or l_oracle_str.ToUpper().IndexOf("BSPR_DEV") > 0 _
            '        Or l_oracle_str.ToUpper().IndexOf("BSPRD") > 0 _
            '        Or l_oracle_str.ToUpper().IndexOf("BSPR_132") > 0 _
            '        Or l_oracle_str.ToUpper().IndexOf("BSPT2") > 0 Then
            '    l_request.AddLine(New ScriptLine("6" & Chr(13), "lhstnew01:/bscs/bscsadm/"))
            'End If

            For commandIndex As Integer = 0 To p_commandList.Length - 1
                If p_commandList(commandIndex).Command.Trim() <> "exit" Then l_request.AddLine(New ScriptLine(p_commandList(commandIndex).Command, p_commandList(commandIndex).ExpectedServerResponseToExecuteNextLine))
            Next

            l_request.AddLine(New ScriptLine("exit", ""))

            l_request.Execute()

        End Sub

        Private _EntryPoint As ScriptLine
        Private _LastLine As ScriptLine
        Private _ExecutingLine As ScriptLine
        Private _TelnetClient As Telnet.TelnetWrapper
        Public _ResponseBuffer As New ArrayList
        Private _MillisecondsTimeout As Integer = Integer.MaxValue

        Public Event ScriptExecutionTimedout(ByVal engine As Script, ByVal line As ScriptLine)
        Public Event ConnectionAttempFailure(ByVal engine As Script)

        Private Sub New(ByVal host As String)
            Me.New(host, 23, Integer.MaxValue)
        End Sub

        Private Sub New(ByVal host As String, ByVal port As Integer)
            Me.New(host, port, Integer.MaxValue)
        End Sub

        Private Sub New(ByVal host As String, ByVal port As Integer, ByVal millisecondsTimeout As Integer)
            Me._TelnetClient = New TelnetWrapper(host, port)
            Me._MillisecondsTimeout = millisecondsTimeout
            AddHandler Me._TelnetClient.ServerRespond, AddressOf OnServerRespond
        End Sub

        Protected Sub OnServerRespond(ByVal sender As Object, ByVal args As Telnet.ServerResponseEventArgs)
            Me._ResponseBuffer.Add(args.Response)
            Try
                args.Command._Response &= args.Response
                args.Command._Responses.Add(args)

                'args.IsExpectedResponse = args.Command._Response.IndexOf(args.Command._ResponseProof) > -1
                'args.IsExpectedResponse = args.Response.IndexOf(args.Command._ResponseProof) > -1
                args.IsExpectedResponse = _
                                            args.Command._Response.ToLower().IndexOf(args.Command._ResponseProof.ToLower()) > -1 _
                                            OrElse _
                                            args.Response.ToLower().IndexOf(args.Command._ResponseProof.ToLower()) > -1
                args.Command._Evaluated = args.IsExpectedResponse
                Return
            Finally
                If args.IsExpectedResponse Then args.Command._Signaler.Set()
            End Try
        End Sub

        Public Sub AddLine(ByVal line As ScriptLine)
            If Me._EntryPoint Is Nothing Then
                Me._EntryPoint = line
            Else
                Me._LastLine._NextLine = line
            End If
            Me._LastLine = line
        End Sub

        Public Sub Execute()
            Me._TelnetClient.Connect()
            If Me._TelnetClient.Connected Then
                Me._EntryPoint.ExecuteRecursive(Me._TelnetClient, Me._MillisecondsTimeout, _ExecutingLine)
                Me._TelnetClient.Disconnect()
                Me._TelnetClient.Close()
                If Not (Me._ExecutingLine Is Me._LastLine AndAlso Me._ExecutingLine._Evaluated) Then
                    Throw New ScriptExecutionException(String.Format("Script execution timed out! Command '{0}' has not returned expected response.", Me._ExecutingLine._Command), Nothing)
                End If
            Else
                Throw New ScriptExecutionException(String.Format("Couldn't connect telnet server '{0}' on port '{1}'", Me._TelnetClient.Hostname, Me._TelnetClient.Port), Nothing)
            End If
        End Sub

        Public ReadOnly Property TelnetClient() As Telnet.TelnetWrapper
            Get
                Return Me._TelnetClient
            End Get
        End Property
    End Class

    Public Class ScriptLine
        Public _Command As String
        Public _ResponseProof As String
        Public _Response As String
        Public _Evaluated As Boolean = False
        Public _NextLine As ScriptLine
        Public _Responses As New ArrayList
        Public _Signaler As New Threading.ManualResetEvent(False)

        Public Sub New(ByVal command As String, ByVal responseProof As String)
            Me._Command = command & Chr(13)
            Me._ResponseProof = responseProof
        End Sub

        Public Sub ExecuteRecursive(ByVal client As Telnet.TelnetWrapper, ByVal milliscondsTimeout As Integer, ByRef executingLine As ScriptLine)
            Dim startDate As DateTime = DateTime.Now
            executingLine = Me
            client.ExecuteExpected(Me)
            Me._Signaler.WaitOne(milliscondsTimeout, False)
            If Not Me._Evaluated Then
                Return
            End If

            Dim finishDate As DateTime = DateTime.Now

            milliscondsTimeout -= New TimeSpan(finishDate.Ticks - startDate.Ticks).TotalMilliseconds

            If Not Me._NextLine Is Nothing Then Me._NextLine.ExecuteRecursive(client, milliscondsTimeout, executingLine)
        End Sub
    End Class

    Public Class ConditionalCommand
        Private _Command As String
        Private _ExpectedServerResponseToExecuteNextLine As String

        Public Sub New(ByVal command As String, ByVal expectedServerResponseToExecuteNextLine As String)
            Me._Command = command
            Me._ExpectedServerResponseToExecuteNextLine = expectedServerResponseToExecuteNextLine
        End Sub

        Public ReadOnly Property Command() As String
            Get
                Return Me._Command
            End Get
        End Property

        Public ReadOnly Property ExpectedServerResponseToExecuteNextLine() As String
            Get
                Return Me._ExpectedServerResponseToExecuteNextLine
            End Get
        End Property
    End Class

    Public Class ScriptExecutionResult
        Private _Success As Boolean = False
        Private _ErrorMessage As String

        Public Sub New(ByVal executionSuccess As Boolean, ByVal errorMEssage As String)
            Me._Success = executionSuccess
            Me._ErrorMessage = errorMEssage
        End Sub

        Public ReadOnly Property Success() As Boolean
            Get
                Return Me._Success
            End Get
        End Property

        Public ReadOnly Property ErrorMessage() As String
            Get
                Return Me._ErrorMessage
            End Get
        End Property
    End Class

    Public Class ScriptExecutionException
        Inherits Exception

        Public Sub New(ByVal message As String, ByVal innerException As Exception)
            MyBase.New(hideConnectionAttributes(message), innerException)
        End Sub


        Private Shared Function hideConnectionAttributes(ByVal messageString) As String
            Dim telnetConnectionAttributes As Collections.Specialized.NameValueCollection = persistent.common.GetConnectionAttributesByConfigKey("telnetConnectionString")
            Dim ftpConnectionAttributes As Collections.Specialized.NameValueCollection = persistent.common.GetConnectionAttributesByConfigKey("ftpConnectionString")

            Dim errorMessage As String = messageString
            errorMessage = errorMessage.Replace(telnetConnectionAttributes("UserName"), "[USERNAME]")
            errorMessage = errorMessage.Replace(telnetConnectionAttributes("Password"), "[PASSWORD]")
            errorMessage = errorMessage.Replace(telnetConnectionAttributes("Server"), "[SERVER]")

            errorMessage = errorMessage.Replace(ftpConnectionAttributes("UserName"), "[USERNAME]")
            errorMessage = errorMessage.Replace(ftpConnectionAttributes("Password"), "[PASSWORD]")
            errorMessage = errorMessage.Replace(ftpConnectionAttributes("Server"), "[SERVER]")

            errorMessage = errorMessage.Replace(ConfigurationSettings.AppSettings("UnixOraUsername"), "[USERNAME]")
            errorMessage = errorMessage.Replace(ConfigurationSettings.AppSettings("UnixOraPassword"), "[PASSWORD]")
            errorMessage = errorMessage.Replace(ConfigurationSettings.AppSettings("UnixOraTNS"), "[SERVER]")

            Return errorMessage
        End Function

    End Class
End Namespace